#include "LecteurPhraseSimple.h"
#include "Exception.h"
#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////

LecteurPhraseSimple::LecteurPhraseSimple(string nomFich) :
ls(nomFich) {
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::analyse() {
    programme();
    cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::programme() {
    // <programme> ::= debut <seqInst> fin FIN_FICHIER

    sauterSymCour("debut");
    seqInst();
    sauterSymCour("fin");
    testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::seqInst() {
    // <seqInst> ::= <inst> ; { <inst> ; }

    do {
        inst();
        sauterSymCour(";");
    } while (ls.getSymCour() == "<VARIABLE>" ||
            ls.getSymCour() == "si" ||
            ls.getSymCour() == "switch" ||
            ls.getSymCour() == "tantque" ||
            ls.getSymCour() == "repeter" ||
            ls.getSymCour() == "lire" ||
            ls.getSymCour() == "ecrire" ||
            ls.getSymCour() == "ecrire_ligne" ||
            ls.getSymCour() == "pour");
    // tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::inst() {
    // <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> |<instlire> |<instEcrire>

    if (ls.getSymCour() == "si") {
        instSi();
    } else if (ls.getSymCour() == "switch") {
        instSwitch();
    } else if (ls.getSymCour() == "tantque") {
        instTq();
    } else if (ls.getSymCour() == "repeter") {
        instRepeter();
    } else if (ls.getSymCour() == "lire") {
        instLire();
    } else if (ls.getSymCour() == "ecrire") {
        instEcrire();
    } else if (ls.getSymCour() == "ecrire_ligne") {
        instEcrire_Ligne();
    } else if (ls.getSymCour() == "pour") {
        instPour();
    } else if (ls.getSymCour() == "<VARIABLE>") {
        affectation();
    }

}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::affectation() {
    // <affectation> ::= <variable> = <expression>

    sauterSymCour("<VARIABLE>");
    sauterSymCour("=");
    if (ls.getSymCour() == "<CHAINE>") {
        ls.suivant();
    } else {
        expression();
    }
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::instSi() { //<instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> }[ sinon <seqInst> ] finsi
    sauterSymCour("si");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    seqInst();

    while (ls.getSymCour() == "sinonsi") {
        ls.suivant();
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
        seqInst();
    }
    if (ls.getSymCour() == "sinon") {
        ls.suivant();
        seqInst();
    }
    sauterSymCour("finsi");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::instSwitch() {// <instSwitch>    ::= switch ( <variable> ) case (<entier>) <seqinst>  { case (<entier>) <seqinst> }
    sauterSymCour("switch");
    sauterSymCour("(");
    sauterSymCour("<VARIABLE>");
    sauterSymCour(")");
    do {
        ls.suivant();
        sauterSymCour("(");
        if (ls.getSymCour() == "<ENTIER>")
            ls.suivant();
        sauterSymCour(")");
        seqInst();
    }while (ls.getSymCour() == "case");
    
    sauterSymCour("finswitch");
};
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::instTq() { //  <instTq> ::= tantque ( <expBool> ) faire <seqInst> fintantque

    sauterSymCour("tantque");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    sauterSymCour("faire");
    seqInst();
    sauterSymCour("fintantque");

}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::instLire() { //      <instLire>      ::= lire ( <variable> )
    sauterSymCour("lire");
    sauterSymCour("(");
    sauterSymCour("<VARIABLE>");
    sauterSymCour(")");

}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::instEcrire() { //      <instEcrire>    ::= ecrire ( <expression> | <chaine> )
    sauterSymCour("ecrire");
    sauterSymCour("(");
    if (ls.getSymCour() == "<VARIABLE>") {
        ls.suivant();
    } else {
        expression();
    }
    sauterSymCour(")");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::instEcrire_Ligne() { //      <instEcrire_Ligne>    ::= ecrire ( <expression> | <chaine> )
    sauterSymCour("ecrire_ligne");
    sauterSymCour("(");
    if (ls.getSymCour() == "<VARIABLE>") {
        ls.suivant();
    } else {
        expression();
    }
    sauterSymCour(")");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::instRepeter() { //  <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )

    sauterSymCour("repeter");
    seqInst();
    sauterSymCour("jusqua");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");

}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::instPour() { //      <instPour>      ::= pour <variable> dans <expression>..<expression> faire <Seqinst> finpour
    sauterSymCour("pour");
    sauterSymCour("<VARIABLE>");
    sauterSymCour("dans");
    expression();
    sauterSymCour("..");
    expression();
    sauterSymCour("faire");
    seqInst();
    sauterSymCour("finpour");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::expBool() { //      <expArith> { <opOu> <expArith> }
    expArith();
    while (ls.getSymCour() == "ou") {
        ls.suivant();
        expArith();
    }

}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::expArith() { //      <relation> { <opEt> <relation> }
    relation();
    while (ls.getSymCour() == "et") {
        ls.suivant();
        relation();
    }

}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::relation() { // <expression> { <opRel> <expression> }
    expression();

    while (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<=" || ls.getSymCour() == ">="
            || ls.getSymCour() == ">" || ls.getSymCour() == "<") {
        ls.suivant();
        expression();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::expression() {
    // <expression> ::= <terme> { <opAdd> <terme> }

    terme();
    while (ls.getSymCour() == "+" || ls.getSymCour() == "-") {
        opAdd();
        terme();
    }

}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::terme() { //<facteur> { <opMult> facteur> }
    facteur();
    while (ls.getSymCour() == "*" || ls.getSymCour() == "/") {
        opMult();
        facteur();
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::facteur() {
    // <facteur> ::= <entier>  |  <variable>  | <opUnaire> <expBool> | ( <expBool> )


    if ((ls.getSymCour() == "-") || (ls.getSymCour() == "non")) {
        ls.suivant();
        expBool();
    } else if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<ENTIER>") {
        ls.suivant();
    } else if (ls.getSymCour() == "(") { // ( <expbool> )
        ls.suivant();
        expBool();

        sauterSymCour(")");
    } else
        erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::opEt() { // et 
    if (ls.getSymCour() == "et")
        ls.suivant();
    else
        erreur("<opEt>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::opOu() { // ou 
    if (ls.getSymCour() == "ou")
        ls.suivant();
    else
        erreur("<opOu>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::opBool() { // == | != | <= | >=
    if (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<=" || ls.getSymCour() == ">="
            || ls.getSymCour() == ">" || ls.getSymCour() == "<")
        ls.suivant();
    else
        erreur("<opBool>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::opAdd() { // + | -
    if (ls.getSymCour() == "+" || ls.getSymCour() == "-")
        ls.suivant();
    else
        erreur("<opAdd>");


}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::opMult() { // * | /
    if (ls.getSymCour() == "*" || ls.getSymCour() == "/")
        ls.suivant();
    else
        erreur("<opMult>");
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::opUnaire()// - | non
{
    if (ls.getSymCour() == "-" || ls.getSymCour() == "non")
        ls.suivant();
    else
        erreur("<opUnaire>");
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::sauterCommentaire() {
    while (ls.iscommentaire())ls.suivant();
}
////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::testerSymCour(string ch) {
    sauterCommentaire();
    if (ls.getSymCour() != ch) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
                << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
                << endl;
        Exerreur e;
        throw e;
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::sauterSymCour(string ch) {
    testerSymCour(ch);
    ls.suivant();
    sauterCommentaire();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseSimple::erreur(string mess) {
    cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
            << ls.getColonne() << endl << "   Attendu : " << mess << endl
            << "   Trouve  : " << ls.getSymCour() << endl << endl;
    Exerreur e;
    throw e;
}
